#pragma once

#include "../EventArgs.h"

class CommandState;
class ViewState;
typedef HWND vSysWindow;
typedef CHAR vSysChar;
typedef uint32 vSysVirtualKey;

/*!class SystemEventArgs
	\brief Abstract system event arguments
*/
class SystemEventArgs : public EventArgs
{
public:
	SystemEventArgs();
	SystemEventArgs(CommandState* pCommandState);
	SystemEventArgs(CommandState* pCommandState,ViewState* viewState);

	virtual bool IsCommandStateEnabled() const;

	virtual bool LButtonDn() const = 0;
	virtual bool RButtonDn() const = 0;
	virtual bool MButtonDn() const = 0;
	virtual bool LButtonUp() const = 0;
	virtual bool RButtonUp() const = 0;
	virtual bool MButtonUp() const = 0;
	virtual bool MouseMove() const = 0;
	virtual bool MouseWheel() const = 0;
	virtual bool LButtonDblClick() const = 0;
	virtual bool RButtonDblClick() const = 0;

	virtual bool LeftAltKeyDown() const = 0;
	virtual bool RightAltKeyDown() const = 0;
	virtual bool LeftCtrlKeyDown() const = 0;
	virtual bool RightCtrlKeyDown() const = 0;
	virtual bool LeftShiftKeyDown() const = 0;
	virtual bool RightShiftKeyDown() const = 0;
	virtual bool CapsLockKeyDown() const = 0;
	virtual bool NumLockKeyDown() const = 0;
	virtual vSysChar GetChar() const = 0;
	virtual vSysVirtualKey GetVirtualKey() const = 0;
	virtual Point GetPhysicalLocation() const = 0;
	virtual short GetWheelDelta() const = 0;
	virtual uint32 GetCommandID() const = 0;
	virtual uint32 GetSysCommandID() const = 0;

	virtual void SetOriginator(vSysWindow window);
	virtual vSysWindow GetOriginator() const;
	virtual void EnableUI(bool bEnable = true);
	virtual void SetUICheck(bool bCheck = true);
	virtual void SetUIRadio(bool bRadio = true);
	virtual void SetUIText(String text);

	virtual void SetCursor(vSysCursor value);
	virtual void ShowCursor(bool show=true);
	virtual void CaptureCursor(bool captured=true);

	virtual void ShowCaret(bool show=true);
	virtual void SetCaretSize(const Size& size);
	virtual void SetCaretPosition(const Point& position);
	virtual void DestroyCaret();

	virtual void SetLocation(const Point& value){m_location = value;}
	virtual const Point& GetLocation() const {return m_location;}

protected:
	vSysWindow m_window;
	CommandState* m_commandState;
	ViewState* m_viewstate;
	Point m_location;
};

class ViewState
{
public:
	ViewState()
	{
		flag = 0u;
	}

	void SetCursor(vSysCursor value){m_cursor.which = value; flag |= cusorwhichChanged;}
	void ShowCursor(bool show=true){m_cursor.visible = show; flag |= cusorvisibleChanged;}
	void CaptureCursor(bool captured=true){m_cursor.captured = captured; flag |= cusorcaptured;}

	void ShowCaret(bool show=true){m_caret.visible = show; flag |= caretvisibleChanged;}
	void SetCaretSize(const Size& size){m_caret.size = size; flag |= caretsizeChanged;}
	void SetCaretPosition(const Point& position){m_caret.position = position; flag |= caretpositionChanged;}
	void DestroyCaret(){flag |= caretdestroyed;}

	bool IsCusorvisibleChanged() const{return flag&cusorvisibleChanged;}
	bool IsCusorwhichChanged() const{return flag&cusorwhichChanged;}
	bool IsCusorcaptured() const{return flag&cusorcaptured;}

	bool IsCaretvisibleChanged() const{return flag&caretvisibleChanged;}
	bool IsCaretsizeChanged() const{return flag&caretsizeChanged;}
	bool IsCaretpositionChanged() const{return flag&caretpositionChanged; }
	bool IsCaretdestroyed() const{return flag&caretdestroyed;}

private:
	enum
	{
		cusorvisibleChanged = 0x0001,	
		cusorwhichChanged = 0x0002,	
		cusorcaptured = 0x0004,

		caretvisibleChanged = 0x0010,
		caretsizeChanged = 0x0020,
		caretpositionChanged = 0x0040,
		caretdestroyed = 0x0080,
	};
	struct Cursor
	{

		Cursor()
		{
			visible = true;
			which = NULL;
			captured = false;
		}
		bool visible;
		vSysCursor which;
		bool captured;
	};
	struct Caret
	{
		Caret()
		{
			visible = true;
		}
		bool visible;
		Size size;
		Point position;
	};

	Caret m_caret;
	Cursor m_cursor;

	uint32 flag;
};

class CommandState
{
public:
	CommandState(uint32 id)
	{
		nCmdID = id;
		bEnable = false;
		bCheck = false;
		bRadio = false;
		flags = 0;
		text = L"";
	}

	void Enable(bool bSet) { bEnable = bSet; flags |= enableChanged; }
	bool IsEnable() const { return bEnable; }
	void SetCheck(bool bSet) { bCheck = bSet; flags |= checkChanged; }
	bool IsCheck() const { return bCheck; }
	void SetRadio(bool bSet) { bRadio = bSet; flags |= radioChanged; }
	bool IsRadio() const { return bRadio; }
	void SetText(const String& str) { text = str; flags |= textChanged; }
	const String& GetText() const{ return text; }
	bool EnableChange() const { return (flags & enableChanged) != 0; }
	bool CheckChanged() const { return (flags & checkChanged) != 0; }
	bool RadioChanged() const { return (flags & radioChanged) != 0; }
	bool TextChanged() const { return (flags & textChanged) != 0; }

	uint32 nCmdID; 

private:
	enum uiChanged
	{
		enableChanged = 1,	
		checkChanged = 2,
		radioChanged = 4,
		textChanged = 8,	
	};

	BYTE flags;
	bool bEnable;
	bool bCheck;
	bool bRadio;
	String text;
};

inline SystemEventArgs::SystemEventArgs() 
	:m_commandState(NULL)
	, m_window(NULL)
	,m_viewstate(NULL)
{}

inline SystemEventArgs::SystemEventArgs(CommandState* pCommandState)
: m_commandState(pCommandState) ,
	m_viewstate(NULL)
{}

inline SystemEventArgs::SystemEventArgs(CommandState* pCommandState,ViewState* viewState)
	: m_commandState(pCommandState) ,
	m_viewstate(viewState)
{
}

inline bool SystemEventArgs::IsCommandStateEnabled() const
{
	return m_commandState!=NULL;
}

inline void SystemEventArgs::SetOriginator(vSysWindow window) 
{
	m_window = window; 
}

inline vSysWindow SystemEventArgs::GetOriginator() const 
{ 
	return m_window; 
}

inline void SystemEventArgs::EnableUI(bool bEnable /*= true*/)
{
	if (m_commandState != NULL)
		m_commandState->Enable(bEnable);
}

inline void SystemEventArgs::SetUICheck(bool bCheck /*= true*/)
{
	if (m_commandState != NULL)
		m_commandState->SetCheck(bCheck);
}

inline void SystemEventArgs::SetUIRadio(bool bRadio /*= true*/)
{
	if (m_commandState != NULL)
		m_commandState->SetRadio(bRadio);
}

inline void SystemEventArgs::SetUIText(String text)
{
	if (m_commandState != NULL)
		m_commandState->SetText(text);
}

inline void SystemEventArgs::SetCursor(vSysCursor value)
{
	if (m_viewstate)
		m_viewstate->SetCursor(value);
}

inline void SystemEventArgs::ShowCursor(bool show/*=true*/)
{
	if (m_viewstate)
		m_viewstate->ShowCursor(show);
}

inline void SystemEventArgs::CaptureCursor(bool captured/*=true*/)
{
	if (m_viewstate)
		m_viewstate->CaptureCursor(captured);
}

inline void SystemEventArgs::ShowCaret(bool show/*=true*/)
{
	if (m_viewstate)
		m_viewstate->ShowCaret(show);
}

inline void SystemEventArgs::SetCaretSize(const Size& size)
{
	if (m_viewstate)
		m_viewstate->SetCaretSize(size);
}

inline void SystemEventArgs::SetCaretPosition(const Point& position)
{
	if (m_viewstate)
		m_viewstate->SetCaretPosition(position);
}

inline void SystemEventArgs::DestroyCaret()
{
	if (m_viewstate)
		m_viewstate->DestroyCaret();
}
